/**

This file is part of MaCI/GIMnet.

MaCI/GIMnet is free software: you can redistribute it and/or modify it 
under the terms of the GNU Lesser General Public License as published 
by the Free Software Foundation, either version 3 of the License, or 
(at your option) any later version.

MaCI/GIMnet is distributed in the hope that it will be useful, but WITHOUT 
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 
FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public 
License for more details.

You should have received a copy of the GNU Lesser General Public 
License along with GIMnet. (See COPYING.LESSER) If not, see 
<http://www.gnu.org/licenses/>.

**/
/**
 * \file
 * \brief UNIX socket implementation header for GIMnetAP.
 * \author Antti Maula <antti.maula@tkk.fi>
 *
 */

#ifndef _CONNECTIONUNIX_H_
#define _CONNECTIONUNIX_H_

#include <sys/poll.h>
#include <sys/un.h> 
#include <netinet/in.h>

#include "connection.h"

#define CONNECTIONUNIX_OK             CONNECTION_OK
#define CONNECTIONUNIX_ERROR          CONNECTION_ERROR


typedef enum { unixStatusConnected, 
               unixStatusDisconnected, 
               unixStatusError } EConnectionUNIXStatus;

typedef enum { unixStyleClient,
	       unixStyleServer } EConnectionUNIXStyle;

typedef enum { unixBlockingTypeBlocking,
	       unixBlockingTypeNonBlocking } EConnectionUNIXBlockingType;

typedef struct _connectionunix {
  EConnectionUNIXStatus connectionStatus;   ///< Status: Connected/DisConnected/Error?
  EConnectionUNIXStyle connectionStyle;     ///< Style; Client / Server?
  EConnectionUNIXBlockingType blockingType; ///< Block; Blocking / non-blocking?

  TConnectionPtr connectionPtr;

  int socket_fd; ///< Socket handle
  int data_fd; ///< Client handle (this is where the data will be written)


  struct sockaddr_un socket_addr;
  struct sockaddr_un socket_addr_remote;

  struct pollfd socket_status;          ///< To check if connection is Ok 

  char socket_file[256];                           ///< Socket file



  pthread_mutex_t mutex;                ///< Connection protection Mutex
} TConnectionUNIX;



/**
 *
 * @param con        Pointer to connection parameters
 *
 */
const TConnectionPtr *connectionUNIXGetConnectionPtrEntry(const TConnectionUNIX *con);


/**
 *
 *
 * @param con        Pointer to connection parameters
 *
 */
int connectionUNIXGetHandle(TConnectionUNIX *con);


/**
 * @param con        Pointer to connection parameters
 *
 */
int connectionUNIXCreateListeningSocket(const char *file, struct sockaddr_un *socket_addr);


/**
 * @param con        Pointer to connection parameters
 *
 */
int connectionUNIXSetSocketHandle(TConnectionUNIX *con, int socket_fd, 
				 struct sockaddr_un *socket_addr);

/**
 * @param con        Pointer to connection parameters
 *
 */
int connectionUNIXSetConnectionType(TConnectionUNIX *con, 
				   EConnectionUNIXStyle style, 
				   EConnectionUNIXBlockingType blocking);

/**
 * @param con        Pointer to connection parameters
 *
 */
int connectionUNIXConnect(TConnectionUNIX *con);


/**
 * @param con        Pointer to connection parameters
 *
 */
int connectionUNIXDisconnect(TConnectionUNIX *con);


/**
 * @param con        Pointer to connection parameters
 *
 */
int connectionUNIXSetSocketFile(TConnectionUNIX *con, const char *file);


/**
 * @param con        Pointer to connection parameters
 *
 */
int connectionUNIXInit(TConnectionUNIX *con);


/**
 * @param con        Pointer to connection parameters
 *
 */
int connectionUNIXDeinit(TConnectionUNIX *con);


/**
 * Sends formatted data. Works just like printf()-family, except
 * that the function requires a pointer to Connection.
 * @param con        Pointer to connection parameters
 * @param format     Format parameter
 * @param ...        Arguments
 * @return           Real number of bytes sent, or negative on error.
 */
int connectionUNIXSendDataFormatted(TConnectionUNIX *con, const char *format, ...);


/**
 * Function that sends raw data over the connection.
 * Connection must be opened with Connect() before this
 * function can be called.
 * The function takes care of connection state checking, so
 * it's always safe to call this function.
 * @param con        Pointer to connection parameters
 * @param buffer     Pointer to data buffer to send
 * @param bufLen     Number of bytes to send
 * @return           Real number of bytes sent, or negative on error.
 */
int connectionUNIXSendData(TConnectionUNIX *con, const unsigned char *buffer, int bufLen);


/**
 * Function that sends raw data over the connection.
 * Connection must be opened with Connect() before this
 * function can be called.
 * The function takes care of connection state checking, so
 * it's always safe to call this function.
 *
 * The 'Ex' in this function means that it's cabable for multibuffer
 * sends. (Reading from separate buffers on a single syscall())
 
 * @param con        Pointer to connection parameters
 * @param bufferA     Pointer to data buffer A to send
 * @param bufLenA     Number of bytes to send from BufferA
 * @param bufferB     Pointer to data buffer B to send
 * @param bufLenB     Number of bytes to send from BufferB
 * @return           Real TOTAL number of bytes sent, or negative on error.
 */
int connectionUNIXSendDataEx(TConnectionUNIX *con, 
			 const unsigned char *bufferA, 
			 int bufLenA,
			 const unsigned char *bufferB, 
			 int bufLenB);

/**
 * Function that receives raw data over the connection.
 * Connection must be opened with Connect() before this
 * function can be called.
 * The function takes care of connection state checking, so
 * it's always safe to call this function.
 * @param con        Pointer to connection parameters
 * @param buffer     Pointer to data buffer to save received data to.
 * @param bufLen     MAXIMUM number of bytes to receive
 * @return           Real number of bytes received, or negative on error.
 */
int connectionUNIXReceiveData(TConnectionUNIX *con, unsigned char *buffer, int bufLen); 


/**
 * Function that receives raw data over the connection.
 * Connection must be opened with Connect() before this
 * function can be called.
 * The function takes care of connection state checking, so
 * it's always safe to call this function.
 * @param con        Pointer to connection parameters
 * @param buffer     Pointer to data buffer to save received data to.
 * @param bufLen     MAXIMUM number of bytes to receive
 * @param timeout_ms Number of milliseconds to wait for new data. Negative
 *                   value means "forever", and zero is ofcourse "now".
 * @return           Real number of bytes received, or negative on error.
 *                   (The zero value means = no new bytes == timeout)
 */
int connectionUNIXReceiveDataTimed(TConnectionUNIX *con, 
			       unsigned char *buffer, 
			       int bufLen,
			       int timeout_ms);


/**
 * Function that receives raw data over the connection.
 * Connection must be opened with Connect() before this
 * function can be called.
 * The function takes care of connection state checking, so
 * it's always safe to call this function.
 * This function differs from the previous one so, that it waits for
 * the full buffer to fill up.
 * @param con        Pointer to connection parameters
 * @param buffer     Pointer to data buffer to save received data to.
 * @param bufLen     Number of bytes to receive
 * @param timeout    Time in milliseconds to wait until the call is considered
 *                   to have timed out. Zero value for infinite wait.
 * @return           Negative value on error, otherwise number of bytes really
 *                   received. NOTE; If the command times out, number of
 *                   read bytes < readBytes.
 */
int connectionUNIXReceiveDataBlock(TConnectionUNIX *con, unsigned char *buffer, int readBytes, int timeout);


/**
 * Function that receives ONE LINE of text, using char 'endChar' as terminating
 * character. Line is returned as endChar stripped.
 * @param con        Pointer to connection parameters
 * @param buffer     Buffer to store data to.
 * @param bufLen     Maximum length of the buffer
 * @param endChar    Character to use for determining EOL. Default is '\n'
 * @return           Number of bytes in line or negative on error.
 */
int connectionUNIXReceiveDataTextLine(TConnectionUNIX *con, char *buffer, int bufLen, char endChar);

#endif //_CONNECTIONUNIX_H_
